﻿using Framework.Domain;
using Framework.Infrastructure;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Framework.EntityFramework
{
    public class DbContextAttribute : System.Attribute
    {
        public string DbContextType { get; set; }
        public DbContextAttribute(string type)
        {
            DbContextType = type;
        }
    }

    public static class EntityExtension
    {
        public static TContext GetDbContext<TContext>(this Entity entity) where TContext : class
        {
            TContext context = default(TContext);
            if (entity.DomainContext != null)
            {
                context = entity.DomainContext as TContext;
            }
            else
            {
                context = IoCFactory.Resolve<TContext>() as TContext;
            }
            return context;
        }

        public static Type GetDbContextType(this Entity entity)
        {
            var attr = entity.GetCustomAttribute<DbContextAttribute>();
            if (attr != null)
            {
                return Type.GetType(attr.DbContextType);
            }
            return null;
        }

        public static DbEntityEntry<TEntity> GetDbEntityEntry<TEntity>(this TEntity entity)
            where TEntity : Entity
        {
            return entity.GetDbContext<MSDbContext>().Entry<TEntity>(entity);
        }

        public static void MarkAsDeleted(this Entity entity)
        {
            entity.GetDbEntityEntry().State = EntityState.Deleted;
        }

        public static void MarkAsAdded(this Entity entity)
        {
            entity.GetDbEntityEntry().State = EntityState.Added;
        }

        public static void MarkAsModified(this Entity entity)
        {
            entity.GetDbEntityEntry().State = EntityState.Modified;
        }

        public static void MarkAsUnchanged(this Entity entity)
        {
            entity.GetDbEntityEntry().State = EntityState.Unchanged;
        }

        public static IQueryable<TElement> GetQueryable<TEntity, TElement>(this TEntity entity, string collectionName)
            where TEntity : Entity
            where TElement : class
        {
            IQueryable<TElement> query = null;
            var entry = entity.GetDbEntityEntry();
            if (entry != null)
            {
                query = entry.Collection(collectionName).Query().Cast<TElement>();
            }
            return query;
        }

        public static IQueryable<TElement> GetQueryable<TEntity, TElement>(this TEntity entity, Expression<Func<TEntity, ICollection<TElement>>> navigationProperty)
            where TEntity : Entity
            where TElement : class
        {
            IQueryable<TElement> query = null;
            var entry = entity.GetDbEntityEntry();
            if (entry != null)
            {
                query = entry.Collection(navigationProperty).Query().Cast<TElement>();
            }
            return query;
        }

        public static void ReferenceLoad<TEntity, TProperty>(this TEntity entity, Expression<Func<TEntity, TProperty>> navigationProperty)
            where TEntity : Entity
            where TProperty : class
        {
            var entry = entity.GetDbEntityEntry<TEntity>();
            if (entry != null)
            {
                entity.GetDbEntityEntry().Reference(navigationProperty).Load();
            }
        }

        public static void CollectionLoad<TEntity, TElement>(this TEntity entity, Expression<Func<TEntity, ICollection<TElement>>> navigationProperty)
            where TEntity : Entity
            where TElement : class
        {
            var entry = entity.GetDbEntityEntry<TEntity>();
            if (entry != null)
            {
                entity.GetDbEntityEntry().Collection(navigationProperty).Load();
            }
        }

    }
}
